home *** CD-ROM | disk | FTP | other *** search
- ---EFFADDR.DOC---
-
- Effective Addresses
-
- Most memory data accessing in the 86 family is accomplished via the mechanism of
- the effective address. Wherever an effective address specifier "eb", "ew" or
- "ed" appears in the list of 8086 instructions, you may use a wide variety of
- actual operands in that instruction. These include general registers, memory
- variables, and a variety of indexed memory quantities.
-
- GENERAL REGISTERS: Wherever an "ew" appears, you can use any of the 16-bit
- registers AX,BX,CX,DX,SI,DI,SP, or BP. Wherever an "eb" appears, you can
- use any of the 8-bit registers AL,BL,CL,DL,AH,BH,CH, or DH. For example,
- the "ADD ew,rw" form subsumes the 16-bit register-to-register adds; for
- example, ADD AX,BX; ADD SI,BP; ADD SP,AX.
-
- MEMORY VARIABLES: Wherever an "ew" appears, you can use a word-memory-variable.
- Wherever an "eb" appears, you can use a byte-memory-variable. Variables are
- typically declared in the DATA segment, using a DW declaration for a word-
- variable, or a DB declaration for a byte-variable. For example, you can
- declare variables:
- DATA_PTR DW ?
- ESC_CHAR DB ?
-
- Later, you can load or store these variables:
- MOV SI,DATA_PTR ; load DATA_PTR into SI for use
- LODSW ; fetch the word pointed to by DATA_PTR
- MOV DATA_PTR,SI ; store the value incremented by the LODSW
- MOV BL,ESC_CHAR ; load the byte-variable ESC_CHAR
-
- Alternatively, you can address specific unnamed memory locations by enclosing
- the location value in square barckets; for example,
- MOV AL,[02000] ; load contents of location 02000 into AL
-
- Note that A86 discerned from context (loading into AL) that a BYTE at 02000
- was intended. Sometimes this is impossible, and you must speicify byte or
- word:
- INC B[02000] ; increment the byte at location 02000
- MOV W[02000],0 ; set the WORD at location 02000 to zero
-
- INDEXED MEMORY: The 86 supports the use of certain registers as base pointers
- and index registers into memory. BX and BP are the base registers; SI and DI
- are the index registers. You may combine at most one base register, at most
- one index register, and a constant number into a run-time pointer that
- determines the location of the effective address memory to be used in the
- instruction. These can be given explicitly, by enclosing the index registers
- in brackets:
- MOV AX,[BX]
- MOV CX,W[SI+17]
- MOV AX,[BX+BP+5]
- MOV AX,[BX][BP]5 ; another way to write the same instruction
-
- Or, indexing can be accomplished by declaring variables in a based structure:
- STRUC [BP] ; NOTE based structures are unique to A86!
- BP_SAVE DW ?
- RET_ADDR DW ?
- PARM1 DW ?
- PARM2 DW ?
- ENDS
- INC PARM1 ; equivalent to INC W[BP+4]
-
- Finally, indexing can be done by mixing explicit components with declared
- ones:
- TABLE DB 4,2,1,3,5
- MOV AL,TABLE[BX]
-
-
- Segmentation and Effective Addresses
-
- The 86 family has four segment registers, CS, DS, ES, and SS, used to address
- memory. Each segment register points to 64K bytes of memory within the 1-
- megabyte memory space of the 86. (The start of the 64K is calculated by
- multiplying the segment register value by 16; i.e., by shifting the value
- left by one hex digit.) If your program's code, data and stack areas can
- all fit in the same 64K bytes, you can leave all the segment registers set to
- the same value. In that case, you won't have to think about segment registers--
- no matter which one is used to address memory, you'll still get the same 64K.
- If your program needs more than 64K, you must point one or more segment
- registers to other parts of the memory space. In this case, you must take
- care that your memory references use the segment registers you intended.
-
- Each effective address memory access has a defualt segment register, to be used
- if you do not explicitly specify which segment register you wish. For most
- effective addresses, the default segment register is DS. The exceptions are
- those effective addresses that use the BP register for indexing. All BP-indexed
- memory references have a default of SS. (This is becuase BP is intended to be
- used for addressing local variables, stored on the stack.)
-
- If you wish your memory access to use a different segment register, you provide
- a segment-override byte before the instruction containing the effective
- address operand. In the A86 language, you code the override by giving the
- name of the segment register you wish before the instruction mnemonic. For
- example, suppose you want to load the AL register with the memory byte pointed
- to by BX. If you code MOV AL,[BX], the DS register will be used to determine
- which 64K segment BX is pointing to. If you want the byte to come from the
- CS-segment instead, you code CS MOV AL,[BX]. Be aware that the segment-override
- byte has effect only upon the single instruction that follows it. If you have
- a sequence of instructions requiring overrides, you must give an override byte
- before every instruction in the sequence. (In that case, you may wish to
- consider changing the value of the default segment register for the duration of
- the sequence.)
-
- NOTE: This method for providing segment-overrides is unique to the A86
- assembler! The assemblers provided by Intel and IBM (MS-DOS) attempt to figure
- out segment allocation for you, and plug in segment-override bytes "behind your
- back". In order to do this, those assemblers require you to inform them which
- variables and structures are pointed to by which segment registers. That is
- what the ASSUME directive in those assemblers is all about. I wrote Intel's
- first 86 assembler, ASM86, so I have been watching the situation since day one.
- Over the years, I have concluded that the ASSUME-mechanism creates far, far
- more confusion that it solves. So I scrapped it; and the result is an assembler
- with far less red tape. But if your program needs more than 64K, you do have
- to manage those segment registers yourself; so take care!
-
-
- Effective Use of Effective Addresses
-
- Remember that all of the common instructions of the 86 family allow effective
- addresses as operands. (The only major functions that don't are the AL/AX
- specific ones: multiply, divide, and input/output). This means that you don't
- have to funnel many through AL or AX just to do something with them. You can
- perform all the common arithmetic, PUSH/POP, and MOVes from any general
- register to any general register; from any memory location (indexed if you
- like) to any register; and (this is most often overlooked) from any register TO
- memory. The only thing you can't do in general is memory-to-memory. Among the
- more common operations that inexperienced 86 programmers overlook are:
-
- * setting memory variables to immediate values
- * testing memory variables, and comparing them to constants
- * preserving memory variables by PUSHing and POPping them
- * incrementing and decrementing memory variables
- * adding into memory variables
-
-
- Encoding of Effective Addresses
-
- Unless you are concerned with the nitty-gritty details of 86 instruction
- encoding, you don't need to read this section.
-
- Every instruction with an effective address has an encoded byte, known as the
- effective address byte, following the 1-byte opcode for the instruction. (For
- obscure reasons, Intel calls this byte the ModRM byte.) If the effective
- address is a memory variable, or an indexed memory location with a non-zero
- constant offset, then the effective address byte will be immediately followed
- by the offset amount. Amounts in the range -128 to +127 are given by a single
- signed byte, denoted by "D8" in the table below. Amounts requiring a 2-byte
- representation are denoted by "D16" in the table below. As with all 16-bit
- memory quantities in the 86 family, the word is stored with the least
- significant byte FIRST.
-
- The following table of effective address byte values is organized into 32
- rows and 8 columns. The 32 rows give the possible values for the effective
- address operand: 8 registers and 24 memory indexing modes. A 25th indexing
- mode, [BP] with zero displacement, has been pre-empted by the simple-memory-
- variable case. If you code [BP] with no displacement, you will get [BP]+D8,
- with a D8-value of zero.
-
- The 8 columns of the table reflect further information given by the effective
- address byte. Usually, this is the identity of the other (always a register)
- operand of a 2-operand instruction. Those instructions are identified by a
- "/r" following the opcode byte in the instruction list. Sometimes, the
- information given supplements the opcode byte in identifying the instruction
- itself. Those instructions are identified by a "/" followed by a digit from
- 0 through 7. The digit tells which of the 8 columns you should use to find
- the effective address byte.
-
- For example, suppose you have a perverse wish to know the precise bytes
- encoded by the instruction SUB B[BX+17],100. This instruction subtracts an
- immediate quantity, 100, from an effective address quantity, B[BX+17]. By
- consulting the instruction list, you find the general form SUB eb,ib. The
- opcode bytes given there are 80 /5 ib. The "/5" denotes an effective-address
- byte, whose value will be taken from column 5 of the table below. The offset
- 17 decimal, which is 11 hex, will fit in a single "D8" byte, so we take our
- value from the "[BX] + D8" row. The table tells us that the effective
- address byte is 6F. Immediately following the 6F is the offset, 11 hex.
- Following that is the ib-value of 100 decimal, which is 64 hex. So the bytes
- generated by SUB B[BX+17],100 are 80 6F 11 64.
-
-
- Table of Effective Address byte values
-
- s = ES CS SS DS
- rb = AL CL DL BL AH CH DH BH
- rw = AX CX DX BX SP BP SI DI
- digit= 0 1 2 3 4 5 6 7
- Effective
- EA byte address:
- values: 00 08 10 18 20 28 30 38 [BX + SI]
- 01 09 11 19 21 29 31 39 [BX + DI]
- 02 0A 12 1A 22 2A 32 3A [BP + SI]
- 03 0B 13 1B 23 2B 33 3B [BP + DI]
- 04 0C 14 1C 24 2C 34 3C [SI]
- 05 0D 15 1D 25 2D 35 3D [DI]
- 06 0E 16 1E 26 2E 36 3E D16 (simple var)
- 07 0F 17 1F 27 2F 37 3F [BX]
- 40 48 50 58 60 68 70 78 [BX + SI] + D8
- 41 49 51 59 61 69 71 79 [BX + DI] + D8
- 42 4A 52 5A 62 6A 72 7A [BP + SI] + D8
- 43 4B 53 5B 63 6B 73 7B [BP + DI] + D8
- 44 4C 54 5C 64 6C 74 7C [SI] + D8
- 45 4D 55 5D 65 6D 75 7D [DI] + D8
- 46 4E 56 5E 66 6E 76 7E [BP] + D8
- 47 4F 57 5F 67 6F 77 7F [BX] + D8
- 80 88 90 98 A0 A8 B0 B8 [BX + SI] + D16
- 81 89 91 99 A1 A9 B1 B9 [BX + DI] + D16
- 82 8A 92 9A A2 AA B2 BA [BP + SI] + D16
- 83 8B 93 9B A3 AB B3 BB [BP + DI] + D16
- 84 8C 94 9C A4 AC B4 BC [SI] + D16
- 85 8D 95 9D A5 AD B5 BD [DI] + D16
- 86 8E 96 9E A6 AE B6 BE [BP] + D16
- 87 8F 97 9F A7 AF B7 BF [BX] + D16
- C0 C8 D0 D8 E0 E8 F0 F8 ew=AX eb=AL
- C1 C9 D1 D9 E1 E9 F1 F9 ew=CX eb=CL
- C2 CA D2 DA E2 EA F2 FA ew=DX eb=DL
- C3 CB D3 DB E3 EB F3 FB ew=BX eb=BL
- C4 CC D4 DC E4 EC F4 FC ew=SP eb=AH
- C5 CD D5 DD E5 ED F5 FD ew=BP eb=CH
- C6 CE D6 DE E6 EE F6 FE ew=SI eb=DH
- C7 CF D7 DF E7 EF F7 FF ew=DI eb=BH
-
- D8 denotes an 8-bit displacement following the EA byte,
- to be sign-extended and added to the index.
-
- D16 denotes a 16-bit displacement following the EA byte,
- to be added to the index.
-
- Default segment register is SS for effective addresses containing
- a BP index; DS for other memory effective addresses.
-